COMMENT % The IMP interface is device number 16. The INPUT subselect MAPFs are: 2 Status Register 4 Data Register The OUTPUT subselect MAPFs are: 0 Clear Input (Reset) 1 Clear Input Full (this clears the input interrupt condition) 2 Clear Output (Reset) 3 Data Output 4 Control Register The Status Register is divided into the following fields: 0:5 Output Counter 6:11 Input Counter 12 Output Empty 13 Output Ready (maintenence use only) 14 Output Needs Data 15 Last IMP Bit 16 Last IMP Bit Seen 17 Input Ready (maintenence use only) 18 Input Full 19 -IMP Ready [DWP was confused] The Control Register is divided as follows: 32 Host Ready 33 Last Output Word 34 Input Interrupt Enable 35 Ouput Interrupt Enable The relevant Status Register information is as follows: Input Counter: This is an UP counter which tells how many places to left shift the Input Data. Output Needs Data: This indicates the interface is ready to accept more output, and causes an interrupt if Output Interrupt is enabled. Note that if Last Host Bit is being sent, Output Empty will be true, but Output Needs Data will be false (and if you try to send a word at this time, you will lose). Last Imp Bit Seen and Input Full both indicate the IMP has finished input to the interface. These cause an interrupt if Input Interrupt is enabled. Output Ready and Input Ready change dynamically during transmission and and on when hardware is ready to transfer a bit. They may change during micro-instruction and should not be depended on. The Control register cannot be read, so a copy of it is kept in the A-MEM. The (scanty) information on the BBN Standard IMP-10 interface, which we are emulating, specify the following CONI and CONO bit assignments: ----------- ----------- ----------- ----------- ----------- ----------- | | | | | | | | | | | | | | |DEV|IMP|ERR| | |EIB| PI CHAN |OUT| PI CHAN |INP| PI CHAN | | |ON |DWN| | | | | | | | | | |---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---| |18 20| |24 |27 | 32|33 35| CONI: Means: Emulated with: 19 Interface is powered On if interface responds with other than -1 20 IMP is now down - IMP Ready 21 IMP has been down (flip-flop simulated in firmware) 24 End of Input Last IMP bit seen (16) 25:27 PI Channel for Bit 24 28 Ready for Output Output Needs Data (14) 29:31 PI Channel for Bit 28 32 Input Ready Input Full (18) 33:35 PI Channel for Bit 32 (Note: by special dispensation, if the Status Register is -1 (meaning the IMP is not connected or something) a CONI returns all bits zero.) (*This code may need to read back END OUT (bit 22) and the PI channels???*) ----------- ----------- ----------- ----------- ----------- ----------- | | | | | | | | | | | |CLR|HST|CLR|END|CLR|SET| LAST BIT |SET|OUTPUT RDY |SET| INPUT RDY | | |ERR|DWN|OUT|OUT|IEB| | PI CHAN | | PI CHAN | | PI CHAN | |---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---| |18 20|21 23|24 26|27 29|30 32|33 35| CONO: Means: Emulated with: 19 Clear IMP has been down (simulated in firmware) 20 Host Down - Host Ready (32) 21 Stop Output Clear Output MAPF 22 End of Output Last Output Word (33) 23 Clear EIB Clear Input, Clear Input Full MAPFs 24 set PI channel in bits 25:27 25:27 PI channel for End of Input (See note below) 28 set PI channel in bits 29:31 29:31 PI channel for Ready for Output 32 set PI for Input Ready channel from bits 33:35 33:35 PI channel for Input Ready (Note: "IMP has been down" is also referred to as the "Error Flop") END OF COMMENT % ;------------------------------------------------------------------------------ ; Definitions for IMP ;------------------------------------------------------------------------------ IMPUDEV = 16 ;uDevice code for first IMP. Second (for Packet Radio) ;must be IMPUDEV+1 for this code to work. ; Input MAPFs IMPI-CONTROL = 2 IMPI-DATA = 4 ; Output MAPFs IMPO-CLEAR-INPUT = 0 IMPO-CLEAR-FULL = 1 IMPO-CLEAR-OUTPUT = 2 IMPO-DATA = 3 IMPO-CONTROL = 4 ; A-Memory IMPA-VECTOR = 0 IMPA-CONTROL = 1 ;Skip 2 - DEST-A-MEM clobbers IR on 2 and 3 IMPA-MASK = 3 IMPA-STATUS = 4 IMPA-HALF = 5 ;First Part Done flag for BLKO .DEFINE D-AMEM[ X ] [ D[X + 8.] ] ;------------------------------------------------------------------------------ ;Instruction Decode ;------------------------------------------------------------------------------ IMPIO2: ;;;Save current location :IMP-IOT ;;;Fill in main instruction decode D[IR] ROT[9. + 1] MASK[1] DEST[Q] NORM $ ;Get type of IMP interface (0 - normal, 1 - packet radio) D[CONST IMPUDEV] ALU[D+Q] DEST[DEV-ADR] JUMP[IMPIO2] NORM $ ;Select aproprate device code ;(Only two instructions allowed above) :IMPIO2 ;;;Resume regular code D[IR] ROT[12. + 1 + 1] MASK[4] DEST[Q] NORM $ ;Get IOT instruction decode ;Extra rotation means two micro-instructions per decode. We ;can do this because indirection and indexing is complete and ;their bits cleared by the time we get here. D-AMEM[IMPA-VECTOR] ROT[18.] MASK[16.] ALU[D+Q] SDISP CYLEN[DISP] $ ;Dispatch according to instruction ;------------------------------------------------------------------------------ ;IOT dispatch for IMP (and IMP2) ;------------------------------------------------------------------------------ IMPDSP: ;BLKI IMP, FIXM2 PUSHJ[BLKI1] $ ;Do first part of BLKI D[MEM] DEST[MA] SPEC[IOB-IN] JUMP[IMPBKI] NORM $ ;Set MA for writing new data (i.e. finish first part of BLKI). ;Start reading data from IMP ;*** This instruction have the same function as IMPIN ;(Continued below) ;DATAI IMP, FIXM2 PUSHJ[IMPIN] $ ;Read word from IMP interface ;While we're at it, make sure we don't page fault later DEST[STRT-WRT] MEMST $ ;Write data into memory. We're done. ;BLKO IMP, FIXM2 PUSHJ[BLKO1] $ ;Do first part of a BLKO instruction D-AMEM[IMPA-CONTROL] DEST[Q] JUMP[IMPBKO] NORM $ ;Copy into Q so we can manipulate control word ;*** This instruction should be same as at IMPOUT ;(Continued below) ;DATAO IMP, FIXM1 PUSHJ[IMPOUT] $ ;Send word to IMP interface DONTSKIP NORM $ ;Start next instruction fetch ;CONO IMP, D[IR] ROT[19.] COND[-OBUS<0] JUMP[IMPCO2] C550 $ ;Jump if not clearing Imp Has Been Down (error flop) D-AMEM[IMPA-STATUS] DEST[Q] JUMP[IMPCNO] NORM $ ;Get status so we can remove that bit ;(Continued below) ;CONI IMP, FIXM2 PUSHJ[IMPSTS] SPEC[IOB-IN] $ ;Get device status. Make sure we don't page fault later. ALU[Q] DEST[MEMSTO] MEMST $ ;Write result into memory. We're done. ;CONSZ IMP, PUSHJ[IMPSTS] SPEC[IOB-IN] NORM $ D[IR] ALU[D&Q] COND[OBUS=0] LBJUMP[SKMAIN] C550 $ ;Decide whether to skip. Start next instruction. ;CONSO IMP, PUSHJ[IMPSTS] SPEC[IOB-IN] NORM $ D[IR] ALU[D&Q] COND[-OBUS=0] LBJUMP[SKMAIN] C550 $ ;Decide whether to skip. Start next instruction. ;------------------------------------------------------------------------------ ;BLKI IMP, (continued) ;------------------------------------------------------------------------------ IMPBKI: MAPF[IMPI-CONTROL] CYLEN[IOB-IN] D[IOD] DEST[AR] PUSHJ[IMPIN1] $ ;Read control register and save it (i.e. second inst. of IMPIN) ;Do second instruction of IMPIN and begin IMPIN ;*** This instruction should be same as at IMPIN+1 D[MEM] DEST[MEMSTO] MEMST $ ;Write data. We're done ;------------------------------------------------------------------------------ ;BLKO IMP, (continued) ;------------------------------------------------------------------------------ IMPBKO: D[CONST 4] ALU[-D&Q] DEST[Q IOD] SPEC[IOB-OUT] PUSHJ[IMPOU1] NORM $ ;Turn off LAST BIT before doing output ;*** This instruction should be same as at IMPOUT+1 ;Finish doing output D[AR] SPEC[LEFT] COND[OBUS=0] JUMP[MAIN] NORM $ ;Check for skip. If not, we're done DOSKIP $ ;Skip return ;------------------------------------------------------------------------------ ;CONO IMP, (continued) ;------------------------------------------------------------------------------ IMPCNO: D[CONST 1] ROT[35. - 21.] ALU[-D&Q] DEST[Q IMPA-STATUS] SPEC[DEST-A-MEM] NORM $ ;Clear Imp Has Been Down IMPCO2: D[IR] ROT[20. + 1] MASK[1] ALU[D+1] DEST[AR] NORM $ ;Extract host down bit. Complement it, sort of. D-AMEM[IMPA-CONTROL] MASK[3] DEST[Q] NORM $ ;Extract all but host ready bit. ;*** Note, if other control bits are added, this code will lose D[AR] ROT[3] MASK[4] ALU[DORQ] DEST[Q] NORM $ ;Turn on host ready bit. Note MASK[4] allow complementing of ;single bit, i.e. 0->01->1, 1->10->0 D[IR] ROT[21.] COND[-OBUS<0] JUMP[IMPCO3] C550 $ ;Stop output? D[CONST 1] ALU[-D&Q] DEST[Q] SPEC[IOB-OUT] NORM $ ;Yes. Stop it from interrupting. Start clearing output MAPF[IMPO-CLEAR-OUTPUT] CYLEN[IOB-OUT] D[IR] ROT[22.] COND[-OBUS<0] JUMP[IMPC3A] $ ;Finish clearing output. ;If not also clearing output, go clear Output Empty. IMPCO3: D[IR] ROT[22.] COND[-OBUS<0] JUMP[IMPCO4] $ ;End of output (message)? D[CONST 5] ALU[DORQ] DEST[Q] SPEC[IOB-IN] NORM $ ;Turn on Last Bit and interrupt enable. (Turned off by next ;DATAO). We'll pass it to the hardware later. ;Read status of device MAPF[IMPI-CONTROL] CYLEN[IOB-IN] D[IOD] DEST[AR] $ ;Latch state of interface, 'cause we can't condition off IOD ;;; D[AR] ROT[12.] COND[OBUS<0] JUMP[IMPC3A] C550 $ ;;; ;Jump if interface isn't done. (We should be here in that case ;;; ;as the programmer is supposed to wait for things to finish.) D[AR] ROT[14.] COND[OBUS<0] JUMP[IMPC3A] C550 $ ;Jump if there's a word already in progress ALU[0] DEST[IOD] SPEC[IOB-OUT] NORM $ ;Interface can't send last bit without having something to ;attach it to. We send a word of zeros, which shouldn't ;matter, as this feature is used only to clear out any stale ;packets when bringing up host. ;MAPF and CYLEN are in case we had to deflower the interface. IMPC3A: MAPF[IMPO-DATA] CYLEN[IOB-OUT] ALU[Q] DEST[IMPA-CONTROL] DEST-A-MEM $ ;Save state of control register D-AMEM[IMPA-STATUS] DEST[Q] NORM $ ;Get status of device into Q where we can use it. D[CONST 1] ROT[35. - 28.] ALU[-D&Q] DEST[IMPA-STATUS] DEST-A-MEM NORM $ ;Turn off Output Ready D-AMEM[IMPA-CONTROL] DEST[Q] JUMP[IMPC4A] $ ;Restore Q from CONTROL IMPCO4: MAPF[IMPO-DATA] CYLEN[IOB-OUT] ALU[Q] DEST[IMPA-CONTROL] SPEC[DEST-A-MEM] $ IMPC4A: D[IR] ROT[23.] COND[-OBUS<0] JUMP[IMPCO5] C550 $ ;Clear input? D[CONST 2] ALU[DORQ] DEST[AR] SPEC[IOB-OUT] NORM $ ;Yes. Set input enable. Clear input buffer. MAPF[IMPO-CLEAR-INPUT] CYLEN[IOB-OUT] D-AMEM[IMPA-STATUS] DEST[Q] SPEC[IOB-OUT] $ ;Clear input done. Get firmware status MAPF[IMPO-CLEAR-FULL] CYLEN[IOB-OUT] D[AR] DEST[IMPA-CONTROL] SPEC[DEST-A-MEM] $ ;Remember new control value. Don't set it yet, let DMA happen ;(We'll pass it to the hardware later.) D[CONST 1] ROT[35. - 24.] ALU[-D&Q] DEST[Q] NORM $ ;Remove Last Bit from status. Finally send out control word ;to hardware! (Remember we set IOD above?) D[CONST 1] ROT[35. - 32.] ALU[-D&Q] DEST[IMPA-STATUS] SPEC[DEST-A-MEM] NORM $ ;Remove Input Full from status. D[CONST 2] DEST[7] DEST-A-MEM SHORT $ ;Set debugging flag for intrpt. routine IMPCO5: D-AMEM[IMPA-MASK] DEST[Q] NORM $ ;Get special mask D[IR] ALU[D&Q] DEST[Q AR] COND[OBUS=0] JUMP[IMPCOX] NORM $ ;Extract channel selection D[AR] ROT[36. - 3] ALU[Q-D] DEST[Q AR] NORM $ ;Make into masks for PI setting. Three separate three ;bit masks, i.e. .xxx.yyy.zzz from x...y...z... D[IR] ALU[D&Q] DEST[HOLD] NORM $ ;Extract new fields D-AMEM[IMPA-STATUS] DEST[Q] NORM $ ;Stupid 2901 D[AR] ALU[-D&Q] DEST[Q] NORM $ ;Remove old PI channel settings D[MEM] ALU[DORQ] DEST[IMPA-STATUS] SPEC[DEST-A-MEM] NORM $ ;Finally, put away PI channel settings to make it easy for CONI D-AMEM[IMPA-CONTROL] DEST[Q] $ ;Cause interrupts if needed D[MEM] ROT[35. - 31.] MASK[3] COND[OBUS=0] JUMP[IMPCO6] $ ;Enable output interrupts if we turned that channel on. D[CONST 1] ALU[DORQ] DEST[Q IMPA-CONTROL] SPEC[DEST-A-MEM] NORM $ ;Yes, enable it. We'll pass it to the hardware later. IMPCO6: D[MEM] ROT[35. - 31.] MASK[3] COND[OBUS=0] JUMP[IMPCOX] $ ;Enable input interrupts if we turned that channel on. D[CONST 2] ALU[DORQ] DEST[Q IMPA-CONTROL] SPEC[DEST-A-MEM] NORM $ ;Yes, enable it. We'll pass it to the hardware later. IMPCOX: D-AMEM[IMPA-CONTROL] DEST[IOD] SPEC[IOB-OUT] NORM $ ;Update hardware. MAPF[IMPO-CONTROL] CYLEN[IOB-OUT] DEST[MA] SPEC[MA_PC] JUMP[MAIN1] $ ;Complete output and start next instruction fetch. ;------------------------------------------------------------------------------ ;IMPSTS Get status from IMP ; ;Description: ; Updates IMP down bits and returns firmware status. ; ;Returns: ; Q: Status ;Called by: IMPCONI,IMPCONSZ,IMPCONSO ;Calls: Nothing ;Clobbers: Q,IOD,AR ;------------------------------------------------------------------------------ IMPSTS: D-AMEM[IMPA-STATUS] DEST[Q] SPEC[IOB-IN] NORM $ ;Copy firmware status into Q MAPF[IMPI-CONTROL] CYLEN[IOB-IN] D[IOD] DEST[AR] PUSHJ[IMPDWC] $ ;Obtain hardware status in AR ;Check IMP down status D[AR] ALU[NOTD] COND[-OBUS=0] POPJ C550 $ ;If we read -1 from device, it isn't really here. ;Otherwise, we're done. ALU[0] DEST[Q] POPJ NORM $ ;Device just plain isn't there. This is what is returned on ;a non-existent device. ;Subroutine to check for host down IMPDWC: D[AR] ROT[19.] COND[-OBUS<0] POPJ C550 $ ;Return if not down D[CONST 1] ROT[35. - 21.] ALU[DORQ] DEST[Q IMPA-STATUS] SPEC[DEST-A-MEM] NORM $ ;Set error flip-flop D[CONST 1] ROT[35. - 20.] ALU[DORQ] DEST[Q] NORM POPJ $ ;Set host down and return. ;------------------------------------------------------------------------------ ;IMPIN Read word from IMP ; ;Returns: ; MEM: Data ;Called by: IMPDATAI,IMPBLKI ;Calls: Nothing ;Clobbers: Q,IOD,AR,HOLD,ROTR,MASKR ; ;Note: To save time at no expense in space, first two instruction here are ; functionally replicated for BLKI IMP, ;------------------------------------------------------------------------------ IMPIN: SPEC[IOB-IN] CYLEN[FIXM] $ ;A write cycle happens here on BLKI ;*** Don't change this without changing BLKI IMP, MAPF[IMPI-CONTROL] CYLEN[IOB-IN] D[IOD] DEST[AR] $ ;Read control register and save it. ;*** Don't change this without changing BLKI IMP, IMPIN1: D[AR] ROT[11. + 1] MASK[6] ALU[0-D] DEST[ROTR] SPEC[IOB-IN] NORM $ ;Setup Rotator. Start reading data MAPF[IMPI-DATA] CYLEN[IOB-IN] D[IOD] ROT[R] DEST[Q HOLD] $ ;Put adjusted data into HOLD (MEM). Save also in Q D[AR] ROT[16.] COND[-OBUS<0] JUMP[IMPIN3] C550 $ ;Jump if not Last Bit Seen, that is, the easy case D[CONST 1] ROT[R] ALU[D-1] COND[OBUS=0] JUMP[IMPIN3] NORM $ ;*** If we read exactly one word, don't mess with it! Note ;*** that we still have to OR in a bit at the bottom (i think) D[AR] ROT[11. + 1] MASK[6] ALU[0-D] DEST[MASKR] NORM $ ;Setup Masker ;;;D[MASK R] ALU[-D&Q] DEST[Q] NORM $ ;*** Assembler blows this one D[2] MASK[R] ALU[-D&Q] DEST[Q] NORM $ ;Sigh... ;Pad with zeros, that is, get rid of extra junk IMPIN2: D[CONST 1] ROT[R] ALU[DORQ] DEST[Q HOLD] NORM $ ;Last bit implies last bit is a one (1). Force it IMPIN3: D-AMEM[IMPA-CONTROL] DEST[Q] SPEC[IOB-OUT] NORM $ ;Get control information into more convenient place ;Setup for next input. MAPF[IMPO-CLEAR-FULL] CYLEN[IOB-OUT] D[CONST 2] ALU[DORQ] DEST[Q IMPA-CONTROL] SPEC[DEST-A-MEM] $ ;Turn on input interrupt enable ALU[Q] DEST[IOD] SPEC[IOB-OUT] SHORT $ ;Tell hardware about this MAPF[IMPO-CONTROL] CYLEN[IOB-OUT] D-AMEM[IMPA-STATUS] DEST[Q] $ ;Finish setting hardware control register. ;Get firmware status D[CONST 1] ROT[35. - 32.] ALU[-D&Q] DEST[IMPA-STATUS] SPEC[DEST-A-MEM] POPJ NORM $ ;Turn off input ready, and return. ;------------------------------------------------------------------------------ ;IMPOUT Output data in MEM to IMP ; ;Description: ; Sends data in MEM to IMP interface. Enables micro-interrupts for ;completion of transfer. ; ;Called by: IMPDATAO,IMPBLKO ;Calls: Nothing ;Clobbers: Q,IOD ; ;Note: To save time at no expense in space, first two instruction here are ; functionally replicated for BLKO IMP, ;------------------------------------------------------------------------------ IMPOUT: D-AMEM[IMPA-CONTROL] DEST[Q] NORM $ ;Copy into Q so we can manipulate control word ;*** Don't change this without changing BLKO IMP, D[CONST 4] ALU[-D&Q] DEST[Q IOD] SPEC[IOB-OUT] NORM $ ;Turn off LAST BIT before doing output ;*** Don't change this without changing BLKO IMP, IMPOU1: MAPF[IMPO-CONTROL] CYLEN[IOB-OUT] D[MEM] DEST[IOD] SPEC[IOB-OUT] $ ;Output data ... MAPF[IMPO-DATA] CYLEN[IOB-OUT] D[CONST 1] ALU[DORQ] DEST[Q IOD] SPEC[IOB-OUT] $ ;Enable output interrupts MAPF[IMPO-CONTROL] CYLEN[IOB-OUT] ALU[Q] DEST[IMPA-CONTROL] SPEC[DEST-A-MEM] $ ;Remember we turned it on. D-AMEM[IMPA-STATUS] DEST[Q] NORM $ ;Turn off bit in status D[CONST 1] ROT[35. - 28.] ALU[-D&Q] DEST[IMPA-STATUS] SPEC[DEST-A-MEM] POPJ NORM $ ;Write it back and we're done ;------------------------------------------------------------------------------ ;IMP Interrupt Code ;------------------------------------------------------------------------------ IMPINT: D-AMEM[IMPA-STATUS] DEST[Q] SPEC[IOB-IN] NORM $ ;Get firmware status while waiting for hardware status. MAPF[IMPI-CONTROL] CYLEN[IOB-IN] D[IOD] DEST[HOLD] $ ;Get hardware status ;;; D[CONST 21] ROT[3] ALU[-D&Q] DEST[Q] NORM $ ;;; ;Remove old Input Full and Output Done status bits D[MEM] ROT[19.] COND[-OBUS<0] JUMP[IMPNT1] C550 $ ;Check for IMP down D[CONST 1] ROT[35. - 21.] ALU[DORQ] DEST[Q IMPA-STATUS] SPEC[DEST-A-MEM] NORM $ ;Set error flip-flop IMPNT1: D[MEM] ROT[14.] COND[-OBUS<0] JUMP[IMPNT2] C550 $ ;Jump if output not waiting. D-AMEM[IMPA-CONTROL] MASK[1] C550 OBUS=0 JUMP[IMPNT2] $ ;Ignore if output ints. not enabled !! D[CONST 1] ROT[35. - 28.] ALU[DORQ] DEST[Q IMPA-STATUS] SPEC[DEST-A-MEM] NORM $ ;Turn on Ready for Output D-AMEM[IMPA-STATUS] ROT[31. + 1] MASK[3] DEST[AR] NORM $ ;Extract PI channel for use by IMPNTS D[CONST 1] DEST[Q] PUSHJ[IMPDIS] NORM $ ;Turn off output interrupts and take macro interrupt if enabled IMPNT2: D[MEM] ROT[18.] COND[-OBUS<0] JUMP[IMPNT5] C550 $ ;Jump if input not ready D[MEM] ROT[16.] COND[OBUS<0] JUMP[IMPNT6] C550 $ ;Jump if both input and last bit at same time. We'll want two ;macro interrupts IMPNT3: D[CONST 1] ROT[35. - 32.] ALU[DORQ] DEST[Q IMPA-STATUS] SPEC[DEST-A-MEM] NORM$ ;Turn on Input Full D-AMEM[IMPA-STATUS] ROT[35. + 1] MASK[3] DEST[AR] NORM $ ;Extract PI channel for use by IMPNTS IMPNT4: D[CONST 2] DEST[Q] PUSHJ[IMPDIS] NORM $ ;Turn off input interrupts and take macro interrupt if enabled IMPNTX: DEST[CLR-DEV-FROM-INTR MA] SPEC[MA_PC] JUMP[MAIN1] NORM $ ;Nothing more to check. Dismiss micro-interrupt IMPNT5: D[MEM] ROT[16.] COND[-OBUS<0] JUMP[IMPNTX] C550 $ ;Done if not last bit seen IMPNT6: D[CONST 1] ROT[35. - 24.] ALU[D&Q] COND[-OBUS=0] JUMP[IMPNT7] NORM $ ;If this is our second time thru, take interrupt for Last Bit D[CONST 1] ROT[35. - 24.] ALU[DORQ] DEST[Q IMPA-STATUS] SPEC[DEST-A-MEM] NORM $ ;Turn on Last Bit Seen ;Input is one and Last Bit is off (or are different) ;;; Always give input full, once only ;;; D[MEM] ROT[5 + 1] MASK[6] DEST[Q] NORM $ ;;; ;Get input bit counter ;;; D[CONST 34] ALU[D-Q] COND[OBUS=0] JUMP[IMPNT7] C550 $ ;;; ;Jump if just last bit on ;;; D-AMEM[IMPA-STATUS] DEST[Q] NORM $ ;;; ;Get new firmware status and mark input buffer full D[CONST 1] ROT[35. - 32.] ALU[DORQ] DEST[IMPA-STATUS] SPEC[DEST-A-MEM] NORM $ D-AMEM[IMPA-STATUS] ROT[35. + 1] MASK[3] DEST[AR] COND[-OBUS=0] JUMP[PIGEN] $ ;Extract PI channel and take interrupt here and now if enabled ;DON'T disable micro input interrupts until we make a second ;PI Request for the Last Bit! IMPNT7: D-AMEM[IMPA-STATUS] ROT[27. + 1] MASK[3] DEST[AR] JUMP[IMPNT4] NORM $ ;Extract PI channel for use by IMPNTS ;------------------------------------------------------------------------------ ;IMPDIS Disable IMP micro-interrupts and take PI if enabled. ; ;Arguments: ; AR: Channel number ; Q: Enable bit (in IMPA-CONTROL) ; ;Note: Restores Q to control IMPA-STATUS. May not return if interrupt is ; taken. ;------------------------------------------------------------------------------ IMPDIS: D-AMEM[IMPA-CONTROL] ALU[D&Q] COND[OBUS=0] JUMP[IMPDSX] C550 $ ;If interrupt disabled, forget it. Restore Q and return D-AMEM[IMPA-CONTROL] ALU[D-Q] DEST[Q IOD] SPEC[IOB-OUT] NORM $ ;Disable interrupt ;We can do subtract since we've already established there's ;a bit to turn off MAPF[IMPO-CONTROL] CYLEN[IOB-OUT] ALU[Q] DEST[IMPA-CONTROL] SPEC[DEST-A-MEM] $ ;Remember enablings as well. D[AR] COND[-OBUS=0] JUMP[PIGEN] NORM $ ;Try to take macro interrupt if channel supplied IMPDSX: D-AMEM[IMPA-STATUS] DEST[Q] POPJ NORM $ ;Get back firmware status and return ;------------------------------------------------------------------------------ ;IMPRST IMP initialization routine ; ;Called by: Reset ;Calls: Nothing ;Clobbers: AMEM[0:7],Q,IOD,DEV-ADR ; ;Note: This code appear after IMPINT and IMPDSP due to forward reference ; problems in CONST expressions. ;------------------------------------------------------------------------------ IMPRST: D[CONST IMPUDEV] DEST[DEV-ADR] $ ;Set device code for initialization ;Entry point for second IMP IMPRS2: ALU[0] DEST[IMPA-CONTROL] SPEC[DEST-A-MEM] NORM $ ;Reset saved control register D[CONST 1] ROT[35. - 19.] DEST[Q] NORM $ D[CONST 1] ROT[35. - 28.] ALU[DORQ] DEST[IMPA-STATUS] DEST-A-MEM NORM $ ;Initially, have just interface present and output ready. ;If harware isn't there, then IMPSTS will return zero. D-AMEM[IMPA-CONTROL] DEST[IOD] SPEC[IOB-OUT] NORM $ ;Clear the device registers ... MAPF[IMPO-CONTROL] CYLEN[IOB-OUT] ALU[0] DEST[IOD] SPEC[IOB-OUT] $ ;Reset control register MAPF[IMPO-CLEAR-OUTPUT] CYLEN[IOB-OUT] SPEC[IOB-OUT] $ ;Clear output side MAPF[IMPO-CLEAR-INPUT] CYLEN[IOB-OUT] ;;; SPEC[IOB-OUT] ;;; ;I don't think we want to start input until we're told via CONO D[CONST 42] ROT[6] DEST[Q] DEST[IOD] $ ;Start construction of mask for PI's and status bits ;Clear input side ;NOTE: input MAPFs must go in this order MAPF[IMPO-CLEAR-FULL] CYLEN[IOB-OUT] D[CONST 10] ALU[DORQ] DEST[IMPA-MASK] SPEC[DEST-A-MEM]$ ;Finish and store mask for PI's and status bits ;Setup entry vectors: IOT vector in left half, interrupt vector in right half D[CONST (IMPDSP / 100)] ROT[18. + 6.] DEST[Q] NORM $ ;hi 6 iot bits D[CONST (IMPDSP \ 100)] ROT[18.] ALU[DORQ] DEST[Q] NORM $ ;low order 6 iot bits D[CONST (IMPINT / 100)] ROT[6.] ALU[DORQ] DEST[Q] NORM $ ;high order 6 interrupt bits D[CONST (IMPINT \ 100)] ROT[0] ALU[DORQ] ;lo 6 intr bits SPEC[DEST-A-MEM] DEST[IMPA-VECTOR] POPJ NORM $ ;Finish setting up vectors and return. ;------------------------------------------------------------------------------ ;BLKI1,BLKI2 Two parts of a BLKI instruction ;------------------------------------------------------------------------------ BLKI1: D[MEM] DEST[Q] NORM $ ;Put IOWD pointer into Q to do incrementing. No HALF test, ;we don't worry about page faults here. D[CONST 1,,1] ALU[D+Q] DEST[Q MEMSTO] COND[-MA-AC] JUMP[BLKI1A] NORM $ ;Increment both halves. (Note: overflow will from right half ;will be added to left half. People who wrap around memory ;deserve what they get!) ACSEL[MA] D[MEM] DEST[AC] CYLEN[MEMSTO] $ ;Also write into AC if needed BLKI1A: D[MEM] SPEC[LEFT] COND[OBUS=0] POPJ CYLEN[MEMSTO] $ ;Finish writing back IOWD pointer. No MAPF needed because of ;FIXM2. ;Return if not skip return D[PC] ALU[D+1] DEST[PC] POPJ NORM $ ;Skip return, take it here .REPEAT 0 [;;;Sample code BLKI2: D[MEM] DEST[MA] PUSHJ[IMP-DATAI-INTERNAL] NORM $ ;Set MA for writing new data ;Fetch data to write ALU[Q] DEST[MEMSTO] MEMST $ ;Write data. We're done ];.REPEAT 0 ;------------------------------------------------------------------------------ ;BLKO1,BLKO2 Two parts of a BLKO instruction ;------------------------------------------------------------------------------ BLKO1: D[MEM] DEST[Q AR] NORM $ D-AMEM[IMPA-HALF] COND[-OBUS=0] JUMP[BLKO1A] C550 $ ;Put IOWD pointer into Q to do incrementing ;Also, put a copy in AR for testing after fetch (page fault) ;Have we been here before? (If so, don't increment) D[CONST 1,,1] ALU[D+Q] DEST[Q AR MEMSTO] COND[-MA-AC] JUMP[BLKO1A] NORM $ ;Increment both halves. (Note: overflow will from right half ;will be added to left half. People who wrap around memory ;deserve what they get!) ;Also, put a copy in AR for testing after fetch (page fault) ACSEL[MA] D[MEM] DEST[AC] CYLEN[MEMSTO] $ ;Also write into AC BLKO1A: ALU[-1] DEST[IMPA-HALF] DEST-A-MEM CYLEN[MEMSTO] $ ;Finish previous write cycle (if not AC). Note that we don't ;need a MAPF field because we've already (should have) done a ;FIXM2 ;Set the First Part Done flag, in case we take a page trap. D[MEM] DEST[MA] CYLEN[MEMSTO] $ ;Set MA for reading new data ACSEL[MA] ALU[AC] DEST[FIXMAC-MAPF-RD] MAPF[BYTE-ILD] CYLEN[FIXM] $ ;Finish reading and go off to output it. This instruction can ;get a page fault. If it does, the PC will be backed up and ;the HALF flag set, which will prevent an extra increment. We ALU[0] DEST[IMPA-HALF] DEST-A-MEM NORM POPJ $ ;also clear it here if we don't page fault. .repeat 0 [;;;Only done in-line BLKO2: D[AR] SPEC[LEFT] COND[OBUS=0] JUMP[MAIN] NORM $ ;Check for skip. If not, we're done DOSKIP $ ;Skip return ];;;.repeat 0